package file

import (
	"errors"
	"flow-calc/common"
	"flow-calc/config"
	"flow-calc/core"
	"flow-calc/flow"
	"fmt"
	"gopkg.in/yaml.v3"
	"io/fs"
	"io/ioutil"
	"path"
	"path/filepath"
)

/**
 *    Description: 配置导入
 *    Date: 2024/4/2
 */

// allConfig 总配置中心(key: 每个配置的名称,如fName,cname,flowName)
type allConfig struct {
	Flows map[string]*config.FlowConfig
	Funcs map[string]*config.FuncConfig
	Conns map[string]*config.ConnectorConfig
}

// kisTypeFlowConfigure 解析yml格式的Flow配置文件
func kisTypeFlowConfigure(all *allConfig, confData []byte, fileName string) error {
	flowConfig := new(config.FlowConfig)
	if err := yaml.Unmarshal(confData, flowConfig); err != nil {
		return err
	}
	// flow 停用状态下不进行加载配置
	if common.OnOff(flowConfig.Status) == common.FlowDisable {
		return nil
	}
	// 加入配置集合
	all.Flows[flowConfig.FlowName] = flowConfig
	return nil
}

// kisTypeFuncConfigure 解析yml格式的Func配置文件
func kisTypeFuncConfigure(all *allConfig, confData []byte, fileName string) error {
	funConfig := new(config.FuncConfig)
	if err := yaml.Unmarshal(confData, funConfig); err != nil {
		return err
	}
	// 加入配置集合
	all.Funcs[funConfig.FName] = funConfig
	return nil
}

// kisTypeConnectorConfigure 解析yml格式的Connector配置文件
func kisTypeConnectorConfigure(all *allConfig, confData []byte, fileName string) error {
	connectorConfig := new(config.ConnectorConfig)
	if err := yaml.Unmarshal(confData, connectorConfig); err != nil {
		return err
	}
	// 加入配置集合
	all.Conns[connectorConfig.Cname] = connectorConfig
	return nil
}

// parseAllYmlConfig 解析所有配置文件
func parseAllYmlConfig(loadPath string) (*allConfig, error) {
	// 初始化工作
	all := new(allConfig)
	all.Flows = make(map[string]*config.FlowConfig)
	all.Funcs = make(map[string]*config.FuncConfig)
	all.Conns = make(map[string]*config.ConnectorConfig)
	// 遍历所有配置文件
	err := filepath.Walk(loadPath, func(filePath string, info fs.FileInfo, err error) error {
		if err != nil {
			return err
		}
		//log.Logger().Debug("文件路径: %s, 文件名称: %s,是否异常: %v", filePath, info.Name(), err)
		// 校验文件类型
		if suffix := path.Ext(filePath); suffix != ".yml" && suffix != ".yaml" {
			//log.Logger().Debug("当前文件类型是: %s, 不符合yaml文件类型,无需加载.", suffix)
			return nil
		}
		// 读取文件
		confData, err := ioutil.ReadFile(filePath)
		if err != nil {
			return err
		}
		confMap := make(map[string]interface{})
		// 校验yaml合法性,进行首次通用转map校验
		if err := yaml.Unmarshal(confData, confMap); err != nil {
			return err
		}
		// 按照类型进行校验
		if kisType, ok := confMap["kisType"]; ok {
			switch kisType {
			case common.FlowType:
				return kisTypeFlowConfigure(all, confData, filePath)
			case common.FuncType:
				return kisTypeFuncConfigure(all, confData, filePath)
			case common.ConnectionType:
				return kisTypeConnectorConfigure(all, confData, filePath)
			default:
				return errors.New(fmt.Sprintf("当前文件: %s, 设置的kisType: %s 无效。", filePath, kisType))
			}
		} else {
			return errors.New("当前配置文件: %s, 没有指定kisType类型。")
		}
	})
	if err != nil {
		return nil, err
	}
	return all, nil
}

// ConfigImportYaml 全盘解析配置文件,yaml格式配置(appointFlow 指定需要加载的flowName名称否则将会加载全部数据)
func ConfigImportYaml(loadPath string, appointFlow ...string) error {
	all, err := parseAllYmlConfig(loadPath)
	if err != nil {
		return err
	}

	for flowName, flowConfig := range all.Flows {
		skip := false
		if len(appointFlow) > 0 {
			for _, flowAppoint := range appointFlow {
				if flowName == flowAppoint {
					skip = true
					break
				}
			}
		}
		if !skip {
			continue
		}
		// 构建一个Flow对象
		newFlow := flow.NewFlow(flowConfig)
		// 加载Flow关联关系
		for _, param := range flowConfig.Flows {
			if err = buildFlow(all, param, newFlow, flowName); err != nil {
				return err
			}
		}
		// 将Flow对象加入到pool管理
		core.Pool().AddFlow(flowName, newFlow)
	}
	return nil
}

// buildFlow 构建flow流
func buildFlow(all *allConfig, fp config.FlowFunctionParam, newFlow core.Flow, flowName string) error {
	if funcConfig, ok := all.Funcs[fp.FName]; !ok {
		return errors.New(fmt.Sprintf("flowName: %s 依赖的funcName: %s 没有配置相关配置。", flowName, fp.FName))
	} else {
		//构建一个connector对象
		if funcConfig.Option.CName != "" {
			if connectorConfig, ok := all.Conns[funcConfig.Option.CName]; !ok {
				return errors.New(fmt.Sprintf("flowName: %s 依赖的funcName: %s 关联的connectorName: %s 没有配置相关配置。", flowName, fp.FName, funcConfig.Option.CName))
			} else {
				// function配置和connector配置进行关联
				_ = funcConfig.AddConnectorConfig(connectorConfig)
			}
		}
		//flow中追加function
		if err := newFlow.Link(funcConfig, fp.Params); err != nil {
			return err
		}
	}
	return nil
}
